#include "../../include/db/user_auth.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../../include/crypto/sm3.h"
#include "../../include/sm2_params.h"
#include <sqlite3.h>
#include "../include/db.h"
#include "../include/auth/sm3_auth.h"

// 获取最后一条日志的哈希值
static int get_last_log_hash(sqlite3 *db, unsigned char *hash, size_t hash_len)
{
    if (!db || !hash || hash_len < SM3_DIGEST_LENGTH)
    {
        return -1;
    }

    sqlite3_stmt *stmt;
    const char *sql = "SELECT current_log_hash FROM audit_log ORDER BY id DESC LIMIT 1;";

    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
    {
        fprintf(stderr, "Failed to prepare statement: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    int result = sqlite3_step(stmt);

    if (result == SQLITE_ROW)
    {
        const void *blob = sqlite3_column_blob(stmt, 0);
        int blob_size = sqlite3_column_bytes(stmt, 0);

        if (blob && blob_size > 0)
        {
            // 确保只复制SM3_DIGEST_LENGTH字节，如果blob_size更大则截断，如果更小则可能不完整
            size_t copy_size = (blob_size >= SM3_DIGEST_LENGTH) ? SM3_DIGEST_LENGTH : (size_t)blob_size;
            memcpy(hash, blob, copy_size);
            if (copy_size < SM3_DIGEST_LENGTH)
            {
                // 如果数据库中的哈希较短，用0填充剩余部分
                memset(hash + copy_size, 0, SM3_DIGEST_LENGTH - copy_size);
            }
        }
        else
        {
            memset(hash, 0, SM3_DIGEST_LENGTH); // 假设是第一条日志或哈希为空
        }
    }
    else if (result == SQLITE_DONE)
    { // No rows returned, means it's the first log
        memset(hash, 0, SM3_DIGEST_LENGTH);
    }
    else
    {
        fprintf(stderr, "Failed to step: %s\n", sqlite3_errmsg(db));
        sqlite3_finalize(stmt);
        return -1;
    }
    sqlite3_finalize(stmt);
    return 0;
}

// 添加审计日志
int add_audit_log(sqlite3 *db, int user_id, const char *operation, const char *file_path, int status_code)
{
    fprintf(stdout, "服务端：准备添加审计日志。用户ID: %d, 操作: %s, 文件路径: %s, 状态码: %d。\n", user_id, operation, file_path ? file_path : "N/A", status_code);
    if (!db || user_id <= 0 || !operation)
    {
        return -1;
    }

    unsigned char prev_hash[SM3_DIGEST_LENGTH];
    fprintf(stdout, "服务端：正在获取上一条审计日志的SM3哈希值...\n");
    if (get_last_log_hash(db, prev_hash, SM3_DIGEST_LENGTH) != 0)
    {
        fprintf(stderr, "Failed to get last log hash.\n");
        fprintf(stdout, "服务端：获取上一条审计日志的SM3哈希值失败。\n");
        return -1;
    }
    // 可以在这里打印 prev_hash (十六进制) 以供调试
    char prev_hash_hex[SM3_DIGEST_LENGTH * 2 + 1];
    for (int i = 0; i < SM3_DIGEST_LENGTH; i++)
        sprintf(prev_hash_hex + i * 2, "%02x", prev_hash[i]);
    prev_hash_hex[SM3_DIGEST_LENGTH * 2] = '\0';
    fprintf(stdout, "服务端：获取到的上一条日志SM3哈希为: %s。\n", prev_hash_hex);

    char log_content[1024];
    time_t now = time(NULL);
    struct tm *tm_info = localtime(&now);
    char timestamp_str[20]; // YYYY-MM-DD HH:MM:SS
    strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", tm_info);

    snprintf(log_content, sizeof(log_content), "%s:%d:%s:%s:%d",
             timestamp_str, user_id, operation,
             file_path ? file_path : "NULL",
             status_code);

    unsigned char current_hash[SM3_DIGEST_LENGTH];
    // 将 prev_hash 和 log_content 拼接起来进行哈希
    // SM3_DIGEST_LENGTH for prev_hash, strlen(log_content) for log_content
    size_t prev_hash_len_to_use = SM3_DIGEST_LENGTH; // 即使prev_hash是全0，也参与计算
    size_t log_content_len = strlen(log_content);
    size_t data_to_hash_len = prev_hash_len_to_use + log_content_len;
    unsigned char *data_to_hash = malloc(data_to_hash_len);
    if (!data_to_hash)
    {
        fprintf(stderr, "Memory allocation failed for hashing audit log.\n");
        return -1;
    }
    memcpy(data_to_hash, prev_hash, prev_hash_len_to_use);
    memcpy(data_to_hash + prev_hash_len_to_use, log_content, log_content_len);

    fprintf(stdout, "服务端：准备使用SM3计算当前审计日志内容的哈希值（链接上一条哈希）。日志原文用于哈希计算部分: '%s'。\n", log_content);
    sm3_hash(data_to_hash, data_to_hash_len, current_hash);
    free(data_to_hash);

    char current_hash_hex[SM3_DIGEST_LENGTH * 2 + 1];
    for (int i = 0; i < SM3_DIGEST_LENGTH; i++)
        sprintf(current_hash_hex + i * 2, "%02x", current_hash[i]);
    current_hash_hex[SM3_DIGEST_LENGTH * 2] = '\0';
    fprintf(stdout, "服务端：当前审计日志的SM3哈希计算完成: %s。\n", current_hash_hex);

    sqlite3_stmt *stmt;
    const char *sql_insert =
        "INSERT INTO audit_log (timestamp, user_id, operation, file_path, status, previous_log_hash, current_log_hash) "
        "VALUES (?, ?, ?, ?, ?, ?, ?);";

    if (sqlite3_prepare_v2(db, sql_insert, -1, &stmt, NULL) != SQLITE_OK)
    {
        fprintf(stderr, "Failed to prepare insert statement for audit_log: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    sqlite3_bind_text(stmt, 1, timestamp_str, -1, SQLITE_STATIC);
    sqlite3_bind_int(stmt, 2, user_id);
    sqlite3_bind_text(stmt, 3, operation, -1, SQLITE_STATIC);

    if (file_path)
        sqlite3_bind_text(stmt, 4, file_path, -1, SQLITE_STATIC);
    else
        sqlite3_bind_null(stmt, 4);

    sqlite3_bind_int(stmt, 5, status_code);

    sqlite3_bind_blob(stmt, 6, prev_hash, SM3_DIGEST_LENGTH, SQLITE_STATIC);
    sqlite3_bind_blob(stmt, 7, current_hash, SM3_DIGEST_LENGTH, SQLITE_STATIC);

    int result = sqlite3_step(stmt);
    sqlite3_finalize(stmt);

    if (result != SQLITE_DONE)
    {
        fprintf(stderr, "Failed to execute insert statement for audit_log: %s (result: %d)\n", sqlite3_errmsg(db), result);
        fprintf(stdout, "服务端：将审计日志 (用户ID: %d, 操作: %s) 存入数据库失败。\n", user_id, operation);
        return -1;
    }
    fprintf(stdout, "服务端：审计日志 (用户ID: %d, 操作: %s) 已成功存入数据库。\n", user_id, operation);
    return 0;
}

// 验证审计日志链的完整性
int verify_audit_log_chain(sqlite3 *db)
{
    if (!db)
        return -1;

    sqlite3_stmt *stmt;
    const char *sql_select =
        "SELECT id, timestamp, user_id, operation, file_path, status, previous_log_hash, current_log_hash "
        "FROM audit_log ORDER BY id ASC;";

    if (sqlite3_prepare_v2(db, sql_select, -1, &stmt, NULL) != SQLITE_OK)
    {
        fprintf(stderr, "Failed to prepare select statement: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    unsigned char expected_prev_hash[SM3_DIGEST_LENGTH];
    memset(expected_prev_hash, 0, SM3_DIGEST_LENGTH); // 第一条日志的期望 prev_hash 为全0

    int valid = 1;

    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
        int id = sqlite3_column_int(stmt, 0);
        const char *timestamp_str = (const char *)sqlite3_column_text(stmt, 1);
        int user_id = sqlite3_column_int(stmt, 2);
        const char *operation = (const char *)sqlite3_column_text(stmt, 3);
        const char *file_path_ptr = (const char *)sqlite3_column_text(stmt, 4);
        int status_val = sqlite3_column_int(stmt, 5);
        const unsigned char *stored_prev_hash = sqlite3_column_blob(stmt, 6);
        int stored_prev_hash_len = sqlite3_column_bytes(stmt, 6);
        const unsigned char *stored_current_hash = sqlite3_column_blob(stmt, 7);
        int stored_current_hash_len = sqlite3_column_bytes(stmt, 7);

        char file_path[256];
        strncpy(file_path, file_path_ptr ? file_path_ptr : "NULL", sizeof(file_path) - 1);
        file_path[sizeof(file_path) - 1] = '\0';

        if (stored_prev_hash_len != SM3_DIGEST_LENGTH || memcmp(stored_prev_hash, expected_prev_hash, SM3_DIGEST_LENGTH) != 0)
        {
            fprintf(stderr, "Audit log chain broken at ID %d: prev_hash mismatch.\n", id);
            valid = 0;
            break;
        }

        if (stored_current_hash_len != SM3_DIGEST_LENGTH)
        {
            fprintf(stderr, "Audit log chain broken at ID %d: invalid current_hash length.\n", id);
            valid = 0;
            break;
        }

        char log_content[1024];
        snprintf(log_content, sizeof(log_content), "%s:%d:%s:%s:%d",
                 timestamp_str, user_id, operation, file_path, status_val);

        unsigned char calculated_current_hash[SM3_DIGEST_LENGTH];
        size_t prev_hash_len_to_use = SM3_DIGEST_LENGTH;
        size_t log_content_len = strlen(log_content);
        size_t data_to_hash_len = prev_hash_len_to_use + log_content_len;
        unsigned char *data_to_hash = malloc(data_to_hash_len);
        if (!data_to_hash)
        {
            fprintf(stderr, "Memory allocation failed for verifying audit log at ID %d.\n", id);
            valid = 0;
            break;
        }
        memcpy(data_to_hash, stored_prev_hash, prev_hash_len_to_use);
        memcpy(data_to_hash + prev_hash_len_to_use, log_content, log_content_len);

        sm3_hash(data_to_hash, data_to_hash_len, calculated_current_hash);
        free(data_to_hash);

        if (memcmp(calculated_current_hash, stored_current_hash, SM3_DIGEST_LENGTH) != 0)
        {
            fprintf(stderr, "Audit log chain broken at ID %d: current_hash mismatch.\n", id);
        }

        memcpy(expected_prev_hash, stored_current_hash, SM3_DIGEST_LENGTH);
    }

    sqlite3_finalize(stmt);
    return valid ? 0 : -1;
}

// 列出审计日志
int list_audit_logs(sqlite3 *db, char ***log_list, int *count, const char *filter)
{
    if (!db || !log_list || !count)
    {
        return -1;
    }

    sqlite3_stmt *stmt;
    const char *sql;

    if (filter && strlen(filter) > 0)
    {
        // 使用过滤条件
        sql = "SELECT id, datetime(timestamp), user_id, operation, ifnull(file_path, 'NULL'), "
              "ifnull(status, 'NULL') FROM audit_log "
              "WHERE operation LIKE ? OR file_path LIKE ? OR status LIKE ? "
              "ORDER BY timestamp DESC LIMIT 100;";

        if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
        {
            return -1;
        }

        char filter_param[128];
        snprintf(filter_param, sizeof(filter_param), "%%%s%%", filter);
        sqlite3_bind_text(stmt, 1, filter_param, -1, SQLITE_STATIC);
        sqlite3_bind_text(stmt, 2, filter_param, -1, SQLITE_STATIC);
        sqlite3_bind_text(stmt, 3, filter_param, -1, SQLITE_STATIC);
    }
    else
    {
        // 不使用过滤条件
        sql = "SELECT id, datetime(timestamp), user_id, operation, ifnull(file_path, 'NULL'), "
              "ifnull(status, 'NULL') FROM audit_log "
              "ORDER BY timestamp DESC LIMIT 100;";

        if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
        {
            return -1;
        }
    }

    // 分配内存以存储结果
    int max_logs = 100; // 初始容量
    *log_list = (char **)malloc(max_logs * sizeof(char *));
    if (!*log_list)
    {
        sqlite3_finalize(stmt);
        return -1;
    }

    *count = 0;

    // 读取结果
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
        int id = sqlite3_column_int(stmt, 0);
        const char *timestamp = (const char *)sqlite3_column_text(stmt, 1);
        int user_id = sqlite3_column_int(stmt, 2);
        const char *operation = (const char *)sqlite3_column_text(stmt, 3);
        const char *file_path = (const char *)sqlite3_column_text(stmt, 4);
        const char *status_str_from_db = (const char *)sqlite3_column_text(stmt, 5);

        char log_entry[1024];
        snprintf(log_entry, sizeof(log_entry), "%d | %s | 用户ID:%d | %s | %s | %s",
                 id, timestamp, user_id, operation, file_path, status_str_from_db ? status_str_from_db : "N/A");

        // 扩容
        if (*count >= max_logs)
        {
            max_logs *= 2;
            char **new_list = (char **)realloc(*log_list, max_logs * sizeof(char *));
            if (!new_list)
            {
                // 内存分配失败，清理并返回
                for (int i = 0; i < *count; i++)
                {
                    free((*log_list)[i]);
                }
                free(*log_list);
                *log_list = NULL;
                *count = 0;
                sqlite3_finalize(stmt);
                return -1;
            }
            *log_list = new_list;
        }

        // 复制日志条目
        (*log_list)[*count] = strdup(log_entry);
        if (!(*log_list)[*count])
        {
            // 内存分配失败，清理并返回
            for (int i = 0; i < *count; i++)
            {
                free((*log_list)[i]);
            }
            free(*log_list);
            *log_list = NULL;
            *count = 0;
            sqlite3_finalize(stmt);
            return -1;
        }

        (*count)++;
    }

    sqlite3_finalize(stmt);
    return 0;
}